package main

import (
	"fmt"
	"github.com/looplab/fsm"
	"time"
)

type CallbackFunc func()

type Door struct {
	To  string
	FSM *fsm.FSM
	Callbacks map[string]CallbackFunc
}

func NewDoor(to string) *Door {
	d := &Door{
		To: to,
	}

	d.FSM = fsm.NewFSM(
		"close",
		fsm.Events{
			{Name: "to_open", Src: []string{"rest", "close"}, Dst: "open"},
			//{Name: "close_open", Src: []string{"close"}, Dst: "open"},
			{Name: "open_close", Src: []string{"open"}, Dst: "close"},
			{Name: "close_rest", Src: []string{"close"}, Dst: "rest"},
		},
		fsm.Callbacks{
			//"enter_state": func(e *fsm.Event) { d.enterState(e) },
			//"after_event": func(e *fsm.Event) { d.afterEvent(e) },
			//"leave_state": func(e *fsm.Event) { d.leaveState(e) },
			//"to_open": func(e *fsm.Event) {
			//	fmt.Println("after to_open: " + e.FSM.Current())
			//
			//	fmt.Println("sss", e.FSM.Can("close"))
			//},
		},
	)
	d.Callbacks = make(map[string]CallbackFunc)
	d.Callbacks["to_open"] = d.open
	d.Callbacks["open_close"] = d.close
	d.Callbacks["close_rest"] = d.rest

	return d
}

func (d *Door) enterState(e *fsm.Event) {
	fmt.Printf("The door to %s is %s\n", d.To, e.Dst)
	//d.Callbacks[e.Dst]()
	fmt.Println("curState ", d.FSM.Current())
}

func (d *Door) leaveState(e *fsm.Event) {
	fmt.Printf("The door leaveState %s is %s\n", d.To, e.Dst)
	//d.Callbacks[e.Dst]()
	fmt.Println("444", d.FSM.Can("close"))
}

func (d *Door) afterEvent(e *fsm.Event) {
	fmt.Println("after ", e.Dst)
	fmt.Println("333", d.FSM.Can("close"))
}

func (d *Door) changeState(event string){
	err := d.FSM.Event(event)
	if err != nil {
		fmt.Println(err)
	}
	if d.Callbacks[event] != nil {
		d.Callbacks[event]()
	}
}

func (d *Door) newTimer(sec time.Duration, f func()){
	ticker := time.NewTicker(sec*time.Second) //定义一个1秒间隔的定时器
	go func() {
		for { //循环
			<-ticker.C
			f()
			ticker.Stop() //停止定时器
		}
	}()
}

func (d *Door) open(){
	fmt.Println("i am open")
	//
	//fmt.Println("sss", d.FSM.Can("close"))
	//fmt.Println("__cllll22", d.FSM.Current())

	//d.newTimer(3, func(){
	//	d.changeState("open_close")
	//})

	for {
		d.changeState("open_close")
		fmt.Printf("_______open__22222222___\n")
		return
	}
}

func (d *Door) close(){
	fmt.Println("i am close")
	d.changeState("close_rest")
}

func (d *Door) rest(){
	fmt.Println("i am rest")
	d.newTimer(1, func(){
		d.changeState("to_open")
	})
}

func FsmStudy() {
	// 创建door对象
	door := NewDoor("heaven")
	// 状态改变，此时对应fsm.Events中的Name：open状态，此时状态由closed转变为open
	fmt.Println("sss", door.FSM.Current())
	fmt.Println("sss", door.FSM.Can("rest"))
	door.changeState("close_rest")
	//door.FSM.Event("close_rest")

}

func main() {
	fmt.Println("fms_________")
	FsmStudy()

	time.Sleep(5*time.Second)
}